InsertCommandBuilder.java
package org.codefilarete.stalactite.sql.order;
import java.sql.PreparedStatement;
import java.util.stream.Collectors;
import org.codefilarete.stalactite.query.builder.SQLBuilder;
import org.codefilarete.stalactite.sql.Dialect;
import org.codefilarete.stalactite.sql.ddl.structure.Column;
import org.codefilarete.stalactite.sql.ddl.structure.Table;
import org.codefilarete.stalactite.sql.statement.ColumnParameterizedSQL;
import org.codefilarete.stalactite.sql.statement.DMLGenerator;
import org.codefilarete.stalactite.sql.statement.PreparedSQL;
import org.codefilarete.stalactite.sql.statement.SQLStatement;
import org.codefilarete.stalactite.sql.statement.binder.ParameterBinder;
import org.codefilarete.stalactite.sql.statement.binder.PreparedStatementWriter;
import org.codefilarete.stalactite.sql.statement.binder.PreparedStatementWriterIndex;
import org.codefilarete.tool.collection.KeepOrderSet;
/**
* A SQL builder for {@link Insert} objects
* Can hardly be mutualized with {@link DMLGenerator} because this class provides
* {@link InsertStatement} which let caller reuse it by setting several time its value through {@link InsertStatement#setValue(Column, Object)}
*
* @author Guillaume Mary
*/
public class InsertCommandBuilder<T extends Table<T>> implements SQLBuilder {
private final Insert<T> insert;
private final Dialect dialect;
public InsertCommandBuilder(Insert<T> insert, Dialect dialect) {
this.insert = insert;
this.dialect = dialect;
}
@Override
public String toSQL() {
KeepOrderSet<? extends Column<T, ?>> columns = insert.getRow().stream().map(ColumnVariable::getColumn).collect(Collectors.toCollection(KeepOrderSet::new));
ColumnParameterizedSQL<T> columnParameterizedSQL = dialect.getDmlGenerator().buildInsert(columns);
return columnParameterizedSQL.getSQL();
}
public InsertStatement<T> toStatement() {
KeepOrderSet<? extends Column<T, ?>> columns = insert.getRow().stream().map(ColumnVariable::getColumn).collect(Collectors.toCollection(KeepOrderSet::new));
ColumnParameterizedSQL<T> columnParameterizedSQL = dialect.getDmlGenerator().buildInsert(columns);
PreparedStatementWriterIndex<Column<T, ?>, PreparedStatementWriter<?>> parameterBinderProvider = columnParameterizedSQL.getParameterBinderProvider();
InsertStatement<T> result = new InsertStatement<>(parameterBinderProvider, columnParameterizedSQL);
insert.getRow().forEach(c -> result.setValue(c.getColumn(), c.getValue()));
return result;
}
/**
* A specialized version of {@link PreparedSQL} dedicated to {@link Insert} so one can set column values of the insert clause
* through {@link #setValue(Column, Object)}.
* Here is a usage example:
* <pre>{@code
* InsertStatement<T> insertStatement = new InsertCommandBuilder<>(this).toStatement(dialect.getColumnBinderRegistry());
* try (WriteOperation<Integer> writeOperation = dialect.getWriteOperationFactory().createInstance(insertStatement, connectionProvider)) {
* writeOperation.setValues(insertStatement.getValues());
* writeOperation.execute();
* }
* // eventually change some values and re-execute it
* insertStatement.setValue(..);
* }</pre>
*/
public static class InsertStatement<T extends Table<T>> extends SQLStatement<Column<T, ?>> {
private final ColumnParameterizedSQL<T> columnParameterizedSQL;
/**
* Single constructor, not expected to be used elsewhere than {@link UpdateCommandBuilder}.
*
* @param parameterBinderProvider binder for prepared statement values
* @param columnParameterizedSQL
*/
private InsertStatement(PreparedStatementWriterIndex<Column<T, ?>, PreparedStatementWriter<?>> parameterBinderProvider, ColumnParameterizedSQL<T> columnParameterizedSQL) {
super(parameterBinderProvider);
this.columnParameterizedSQL = columnParameterizedSQL;
}
@Override
public String getSQL() {
return columnParameterizedSQL.getSQL();
}
@Override
protected void doApplyValue(Column<T, ?> key, Object value, PreparedStatement statement) {
PreparedStatementWriter<Object> paramBinder = getParameterBinder(key);
if (paramBinder == null) {
throw new BindingException("Can't find a " + ParameterBinder.class.getName() + " for column " + key.getAbsoluteName() + " of value " + value
+ " on sql : " + getSQL());
}
doApplyValue(columnParameterizedSQL.getColumnIndexes().get(key)[0], value, paramBinder, statement);
}
}
}